package algocity.modelo.juego;

import algocity.modelo.mapa.Mapa;
import algocity.modelo.zona.Construccion;
import algocity.modelo.zona.Industrial;
import algocity.modelo.zona.Residencial;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;


/**
 * Supuestos :
 *  - hay 4 personas por familia y  2 de ellas trabajan (la mitad de la población trabaja)
 *  - si hay maś empleos que familias que trabajan el bienestar sube
 *  - cuantas mejor la relación zonas comerciales / residenciales más bienestar
 */

public class MinisterioDeBienestarSocial
    implements Trabajable<ObjetoNulo>, Serializable {

    private final List<Integer> registroHabitantes;
    private Mapa mapa;
    private RecolectorConstrucciones recolectorZonas;
    private int bienestar;
    private int censadosUsable;
    private int empleosUsable;

    public MinisterioDeBienestarSocial(Mapa mapa) {
        this.mapa = mapa;
        this.registroHabitantes = new ArrayList<Integer>();
        registroHabitantes.add(0);
        reset();
    }

    private void reset() {
        recolectorZonas  = new RecolectorConstrucciones();
        bienestar = 0;
        censadosUsable = 0;
        empleosUsable = 0;
    }

    public Boolean trabajar(ObjetoNulo parametro) {
        censar();
        calcularBienestar();
        ajustarHabitantes();
        reset();
        return Boolean.TRUE;
    }

    private void calcularBienestar() {

        int residencias =
                ColeccionesAlgoCity.filtrar(recolectorZonas.getConstrucciones(), new ComparadorResidencias()).size();

        int numComercios =
                ColeccionesAlgoCity.filtrar(recolectorZonas.getConstrucciones(), new ComparadorComercios()).size();


        // Familia compuesta por 2 personas que trabajan y 2 que no trabajan. A más empleos mejor.
        int factorTrabajo = (censadosUsable == 0) ? 0 : (empleosUsable / (censadosUsable / 2) ) ;
        int factorEsparcimiento  = residencias == 0 ? 0 : numComercios / ( 5 * residencias );

        this.bienestar = factorEsparcimiento + factorTrabajo;
    }

    private void ajustarHabitantes() {

        int nuevoCenso = 0;
        double factorDeAjuste = 0.9 + bienestar ;

        for ( Construccion construccion : ColeccionesAlgoCity.filtrar(recolectorZonas.getConstrucciones(), new ComparadorResidencias()) ) {
            Residencial residencial = (Residencial) construccion;
            final double alojados = residencial.getCantidadDeGenteAlojada() * factorDeAjuste;
            nuevoCenso += alojados;
            residencial.setCantidadDeGenteAlojada((int) alojados);
        }

        for ( Construccion construccion : ColeccionesAlgoCity.filtrar(recolectorZonas.getConstrucciones(), new ComparadorIndustrias()) ) {
            Industrial industrial = (Industrial) construccion;
            final double alojados = industrial.getEmpleados() * factorDeAjuste;
            nuevoCenso += alojados;
            industrial.setEmpleados((int) alojados);
        }

        registroHabitantes.add(nuevoCenso);
        mapa.setPoblacion(nuevoCenso);

    }

    private void censar() {
        mapa.scan(recolectorZonas);

        for ( Construccion construccion: ColeccionesAlgoCity.filtrar(recolectorZonas.getConstrucciones(), new ComparadorResidencias())) {
            Residencial residencial = (Residencial) construccion;
            final int cantidadDeGenteAlojada = residencial.getCantidadDeGenteAlojada();
            if ( residencial.esUsable()) {
                censadosUsable += cantidadDeGenteAlojada;
            }
        }

        for ( Construccion construccion : ColeccionesAlgoCity.filtrar(recolectorZonas.getConstrucciones(), new ComparadorIndustrias())) {
            Industrial industria = (Industrial) construccion;
            final int empleosOfrecido = industria.getCapacidadDeEmpleo();
            if ( industria.esUsable() ) {
                empleosUsable += empleosOfrecido;
            }
        }

    }

    public int obtenerBalance() {
        int ultimo = registroHabitantes.size() - 1;

        if ( ultimo < Parametros.MINIMA_CANTIDAD_DE_REGISTROS_PARA_ACUMULAR_PUNTAJE) {
            return 0;
        }

        return registroHabitantes.get(ultimo) - registroHabitantes.get(ultimo - 1);
    }

    public int obtenerUltimoCenso() {
        return registroHabitantes.get( registroHabitantes.size() - 1 );
    }
}
